/*
 * FileAsMsg plug-in for Miranda IM and QIP Infium.
 * Sending/receiving files via instant messaging without protocol support.
 * Homepage: http://code.google.com/p/fileasmsg/
 *
 * Copyright (c) 2008, Radist <radist.nt@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Name(s) of contributor(s) may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Radist ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Radist BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __FILEASMESSAGE_QIP_PLUGIN_H__R___

#include <Windows.h>
#include <process.h>
#include <u_common.h>
#include <u_plugin_msg.h>
#include <u_plugin_info.h>
#define OPENSSL_NO_SHA0
#define OPENSSL_NO_SHA256
#define OPENSSL_NO_SHA512
#include <openssl/sha.h>

//SHA1 interface
typedef struct {
	int (*_Init)(SHA_CTX *c);
	int (*_Update)(SHA_CTX *c, const void *data, size_t len);
	int (*_Final)(unsigned char *md, SHA_CTX *c);
} SHA_INT;
extern SHA_INT SHA1i;

#define SHA1_HASH_SIZE SHA_DIGEST_LENGTH
#define SHA1_CTX SHA_CTX
#define sha1_init(pctx) SHA1i._Init(pctx)
#define sha1_append(pctx,data,len) SHA1i._Update(pctx, data, len)
#define sha1_finish(pctx,_hash) SHA1i._Final(_hash, pctx)

//Memory interface
#define _malloc(x) malloc(x)
#define _calloc(x) calloc(x)
#define _free(x) free(x)
#define _realloc(x,y) realloc(x,y)
//#define _strdup(x) strdup(x)
#define _wstrdup(x) _wcsdup(x)
#define _tstrdup(x) _tcsdup(x)

wchar_t* MBtoWide(const char* str, UINT codepage);
char* WidetoMB(const wchar_t* str, UINT codepage);
#define _a2u(x) MBtoWide(x, CP_ACP)
#define _u2a(x) WidetoMB(x, CP_ACP)
#define _utf8decodeW(x) MBtoWide(x, CP_UTF8)
#define _utf8encodeW(x) WidetoMB(x, CP_UTF8)

#define SendIMMsg(hContact,msg,_utf8) PluginIntf->SendMsg(hContact, msg, _utf8)
#define ForkThread(start,param,idptr) (HANDLE)_beginthreadex(NULL, 0, start, param, 0, idptr)
#define SaveWndPos(hWnd, hContact, NamePrefix) \
	if (hContact) \
	{ \
		RECT rect; \
		if (GetWindowRect(hWnd, &rect)) \
		{ \
			wchar_t nums[16], *cName = GetContactName(hContact); \
			swprintf_s(nums, L"%d,%d", rect.left, rect.top); \
			WritePrivateProfileStringW(ContactHandlesConverter::GetContactProtocolByHandle(hContact), cName, nums, PluginIntf->GetIniFileName()); \
			_free(cName); \
		} \
	}
#define LoadWndPos(hWnd, hContact, NamePrefix) \
	if (hContact) \
	{ \
		wchar_t nums[16], *cName = GetContactName(hContact); \
		GetPrivateProfileStringW(ContactHandlesConverter::GetContactProtocolByHandle(hContact), cName, L"", nums, sizeof(nums)/sizeof(nums[0]), PluginIntf->GetIniFileName()); \
		_free(cName); \
		if (nums[0]) \
		{ \
			int x = wcstol(nums, &cName, 10), y = wcstol(cName + 1, &cName, 10); \
			SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER); \
		} \
	}
#define GetContactName(hContact) ContactHandlesConverter::GetContactNameByHandle(hContact)

//////////////////////////////////////////////////////////////////////////

#define TranslateW(x) x
#define Translate(x) x
#define LPGEN(x) x
#define LPGENW(x) L ## x
#define TranslateDialogDefault(x)

//from m_database.h
#define DBEF_RTL      8    //event contains the right-to-left aligned text
#define DBEF_UTF     16    //event contains a text in utf-8


//////////////////////////////////////////////////////////////////////////
// Plug-in interface's class

#include <map>

class ContactHandlesConverter
{
	typedef struct {
		HANDLE ProtoHandle;
		const wchar_t* ProtoName;
		wchar_t ContactName[1];
	} *pSContact;
	struct proto_st {
		bool operator()(const wchar_t* l, const wchar_t* r)const
		{
			return wcscmp(l, r)<0;
		}
	};

	typedef std::multimap<DWORD_PTR, pSContact> ContactsTable;
	typedef std::map<wchar_t*, HANDLE, proto_st> ProtocolsTable;
	typedef std::map<HANDLE, wchar_t*> ProtocolHndlTable;

	ContactsTable contacts;
	ProtocolsTable protos;
	ProtocolHndlTable hs;
	DWORD_PTR GetStrHash(const wchar_t* str);
	HANDLE GetProtoHandle(BSTR ProtoName, const wchar_t **NamePtr = NULL);
public:
	ContactHandlesConverter();
	~ContactHandlesConverter();

	wchar_t* NotifyProtoHandle(HANDLE ProtoHandle, BSTR ProtoName);
	HANDLE GetContactHandle(BSTR ProtoName, BSTR ContactName, HANDLE proto = NULL);
	inline HANDLE GetContactProtocolHandleByHandle(HANDLE hContact)
	{
		return static_cast<pSContact>(hContact)->ProtoHandle;
	}
	static inline const wchar_t* GetContactNameByHandlePtr(HANDLE hContact)
	{
		if (hContact) return static_cast<pSContact>(hContact)->ContactName;
		else return NULL;
	}
	static inline wchar_t* GetContactNameByHandle(HANDLE hContact)
	{
		const wchar_t* res = GetContactNameByHandlePtr(hContact);
		return res ? _wstrdup(res) : NULL;
	}
	static inline const wchar_t* GetContactProtocolByHandle(HANDLE hContact)
	{
		if (hContact) return static_cast<pSContact>(hContact)->ProtoName;
		else return NULL;
	}
};

class FAMPlugin
	: IQIPPlugin
{
	IQIPPluginService* service;
	PluginInfo plugininfo;
	PluginSpecific* settings;
	ContactHandlesConverter converter;
	wchar_t* ini_filename;
	int ref_counter;
	HWND PlugWnd;
	AddBtnInfo button;
	bool enabled;
	bool running;

	FAMPlugin(IQIPPluginService* svc);
	~FAMPlugin();

	static LRESULT CALLBACK PlugWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	void InitInfo(void);
	void AddBtn(void);
	void InitSend(wchar_t* AccName, HANDLE AccProto, HANDLE AccHandle);
	void RunPlugin(void);
	void QuitPlugin(void);
public:
	static IQIPPlugin* GetInstance(IQIPPluginService* svc);

	//IUnknown methods
	virtual HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObject);
	virtual ULONG __stdcall AddRef(void);
	virtual ULONG __stdcall Release(void);

	//IQIPPlugin methods
	virtual PluginInfo* __stdcall GetPluginInfo();
	virtual void __stdcall OnQipMessage(PluginMessage* plugMsg);

	HANDLE SendMsg(HANDLE hContact, const char* message, bool utf8);
	wchar_t* GetIniFileName(void);
};

extern FAMPlugin* PluginIntf;

#define __FILEASMESSAGE_QIP_PLUGIN_H__R___
#endif//__FILEASMESSAGE_QIP_PLUGIN_H__R___
